import json
import re
from django.contrib.auth import login, logout
from django.shortcuts import render
from django import http
from django.shortcuts import redirect
from django.urls import reverse
from django.views import View
from django_redis import get_redis_connection

from apps.carts.utils import merge_cookie_to_redis
from apps.goods.models import SKU
from apps.users.models import User, Address
from django.contrib.auth import authenticate
from django.contrib.auth.mixins import LoginRequiredMixin

from apps.users.utils import generic_verify_email_url, check_verify_email_token
from utils.response_code import RETCODE
from utils.views import LoginRequiredJSONMixin
import logging

logger = logging.getLogger('django')


class RegisterView(View):
    def get(self, request):
        return render(request, 'register.html')

    def post(self, request):
        data = request.POST
        username = data.get("username")
        password = data.get("password")
        password2 = data.get("password2")
        mobile = data.get("mobile")
        allow = data.get("allow")
        sms_code_client = data.get("sms_code")

        if not all([username, password, password2, mobile, allow, sms_code_client]):
            return http.HttpResponseBadRequest("缺少必传参数！")
        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
            return http.HttpResponseBadRequest("请输入5-20个字符！")
        if not re.match(r'^[a-zA-Z0-9\.,_-]{8,20}$', password):
            return http.HttpResponseBadRequest("请输入8-20为密码！")
        if password2 != password:
            return http.HttpResponseBadRequest("两次输入的密码不一致！")
        if not re.match(r'^1[3-9]\d{9}', mobile):
            return http.HttpResponseBadRequest("请输入正确的手机号码！")
        if allow != "on":
            return http.HttpResponseBadRequest("请勾选用户协议！")
        # 验证短信验证码
        # 1.连接redis数据库
        redis_conn = get_redis_connection('code')
        # 2.获取redis中的短信验证码
        sms_code_server = redis_conn.get('sms_%s' % mobile)
        # 3.验证redis中的短信验证码是否过期
        if not sms_code_server:
            return http.HttpResponseBadRequest('短信验证码已失效！')
        # 4.验证短信验证码是否一致
        if sms_code_server.decode() != sms_code_client:
            return http.HttpResponseBadRequest('短信验证码不一致')
        try:
            user = User.objects.create_user(
                username=username,
                password=password,
                mobile=mobile
            )
        except Exception as e:
            print(e)
            return render(request, 'register.html', context={"register_errmg"})

        login(request, user)

        response = redirect(reverse('contents:index'))
        response.set_cookie('username', user.username, max_age=14 * 24 * 3600)
        return response
        # return HttpResponse("ok")


class UsernameCountView(View):
    def get(self, request, username):
        count = User.objects.filter(username=username).count()
        return http.JsonResponse({"count": count})


class MobileCountView(View):
    def get(self, request, mobile):
        count = User.objects.filter(mobile=mobile).count()
        return http.JsonResponse({"count": count})


# 登录用户
class LoginView(View):
    def get(self, request):
        return render(request, 'login.html')

    def post(self, request):
        data = request.POST
        username = data.get('username')
        password = data.get('password')
        remembered = data.get('remembered')
        if not all([username, password]):
            return http.HttpResponseBadRequest('缺少必传参数')
        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
            return http.HttpResponseBadRequest("请输入5-20个字符！")
        if not re.match(r'^[a-zA-Z0-9\.,_-]{8,20}$', password):
            return http.HttpResponseBadRequest("请输入8-20为密码！")
        user = authenticate(username=username, password=password)
        if user is None:
            return render(request, 'login.html', {"login_error_message": "用户名或密码错误"})
        login(request, user)
        if remembered != 'on':
            request.session.set_expiry(0)
        else:
            request.session.set_expiry(None)
        next = request.GET.get('next')
        if next:
            response = redirect(next)
        else:
            response = redirect(reverse("contents:index"))

        if remembered != 'on':
            response.set_cookie('username', user.username, max_age=None)
        else:
            response.set_cookie('username', user.username, max_age=14 * 24 * 3600)
        response = merge_cookie_to_redis(request=request, user=user, response=response)

        return response


# 退出用户
class LogoutView(View):
    def get(self, request):
        logout(request)

        response = redirect(reverse('contents:index'))

        response.delete_cookie('username')
        return response


# 用户中心
class UserInfoView(LoginRequiredMixin, View):
    def get(self, request):
        context = {
            "username": request.user.username,
            "mobile": request.user.mobile,
            "email": request.user.email,
            "email_active": request.user.email_active
        }
        return render(request, 'user_center_info.html', context=context)

    """
    确定请求方式和路由 PUT
    步骤：
        1.必须是登录用户才可以更新邮箱信息
        2.接受用户提交的邮箱信息
        3.验证邮箱信息是否符合邮箱规则
        4.保存数据
        5.发送激活邮件
        6.返回响应

        GET  ： 获取数据
        POST ： 增加数据
        PUT  ： 更新或修改数据
        DELETE ： 删除数据
    """


# 发送邮件
class EmailView(LoginRequiredJSONMixin, View):
    def put(self, request):
        body = request.body
        body_str = body.decode()
        data = json.loads(body_str)
        email = data.get('email')
        if not email:
            return http.JsonResponse({'code': RETCODE.NECESSARYPARAMERR, 'errmsg': '缺少参数'})
        if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
            return http.JsonResponse({'code': RETCODE.PARAMERR, 'errmsg': '参数错误'})

        try:
            request.user.email = email
            request.user.save()
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '更新错误'})
        from django.core.mail import send_mail
        """
        subject 邮件标题
        message 普通邮件正文，普通字符串
        from_email 发件人
        recipient_list 收件人列表
        html_message 多媒体邮件正文，可以是html字符串
        """
        subject = "主题"
        message = "美多商城"
        from_email = "lyw_0017@163.com"
        recipient_list = ["lyw_0017@163.com"]
        # 加密token
        verify_url = generic_verify_email_url(request.user.id)
        html_message = '<p>尊敬的用户您好！</p>' \
                       '<p>感谢您使用美多商城。</p>' \
                       '<p>您的邮箱为：%s 。请点击此链接激活您的邮箱：</p>' \
                       '<p><a href="%s">%s<a></p>' % (email, verify_url, verify_url)
        # send_mail(
        #     subject=subject,
        #     message=message,
        #     from_email=from_email,
        #     recipient_list=recipient_list,
        #     html_message=html_message
        # )
        from celery_tasks.email.tasks import send_verify_email
        send_verify_email.delay(
            subject=subject,
            message=message,
            from_email=from_email,
            recipient_list=recipient_list,
            html_message=html_message
        )

        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK'})


# 邮件激活
class EmailVerifyView(View):
    def get(self, request):
        data = request.GET
        # 接受token
        token = data.get('token')

        if token is None:
            return http.HttpResponseBadRequest('参数错误!')
        # 验证token 解密
        user_id = check_verify_email_token(token)
        if user_id is None:
            return http.HttpResponseBadRequest('参数错误!')
        try:
            user = User.objects.get(pk=user_id)
            if user is not None:
                user.email_active = True
                user.save()

        except User.DoesNotExist:
            return http.HttpResponseBadRequest('参数错误!')

        return redirect(reverse('users:info'))


# 查询收货地址
class AdressView(LoginRequiredMixin, View):
    """
    1.必须是登录用户
    2.查询登录用户的地址信息(Address,Address)
    3.对列表数据进行转换字典列表操作
    4.传递给模板
    """

    def get(self, request):
        # 查询登录用户的地址信息(Address,Address)
        addresses = Address.objects.filter(user=request.user, is_deleted=False)
        # 对列表数据进行转换字典列表操作
        address_list = []
        for address in addresses:
            address_list.append({
                "id": address.id,
                "title": address.title,
                "receiver": address.receiver,
                "province": address.province.name,
                "province_id": address.province_id,
                "city": address.city.name,
                "city_id": address.city_id,
                "district": address.district.name,
                "district_id": address.district_id,
                "place": address.place,
                "mobile": address.mobile,
                "tel": address.tel,
                "email": address.email
            })
        context = {
            "addresses": address_list,
            "default_address_id": request.user.default_address_id
        }
        return render(request, "user_center_site.html", context=context)


# 新增收货地址
class CreateAddressView(LoginRequiredJSONMixin, View):
    # 需求:
    #     1.判断用户是否登录
    #     2.接受参数
    #     3.检验参数
    #     4.数据入库
    #     5.返回响应
    def post(self, request):
        # 判断收货地址是否超过20个
        count = Address.objects.filter(user=request.user, is_deleted=False).count()
        if count > 20:
            return http.JsonResponse({"code": RETCODE.THROTTLINGERR, "errmsg": "个数超过限制"})
        # 判断用户是否登录

        # 接受参数
        json_dict = json.loads(request.body.decode())
        receiver = json_dict.get('receiver')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')

        # 检验参数
        if not all([receiver, province_id, city_id, district_id, place, mobile]):
            return http.HttpResponseBadRequest('缺少必传参数')
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseBadRequest('参数mobile有误')
        if tel:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
                return http.HttpResponseBadRequest('参数tel有误')
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return http.HttpResponseBadRequest('参数email有误')

        # 保存地址信息
        try:
            address = Address.objects.create(
                user=request.user,
                title=receiver,
                receiver=receiver,
                province_id=province_id,
                city_id=city_id,
                district_id=district_id,
                place=place,
                mobile=mobile,
                tel=tel,
                email=email
            )
            # 如果没有默认地址，就设置一个默认地址
            if not request.user.default_address:
                request.user.default_address = address
                request.user.save()
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({"code": RETCODE.DBERR, "errmsg": "数据操作失败"})

        # 返回响应
        address_dict = {
            "id": address.id,
            "title": address.title,
            "receiver": address.receiver,
            "province": address.province.name,
            "city": address.city.name,
            "district": address.district.name,
            "place": address.place,
            "mobile": address.mobile,
            "tel": address.tel,
            "email": address.email
        }
        return http.JsonResponse({"address": address_dict, "code": RETCODE.OK, })


# 修改、更新和删除收货地址
class UpdateDestoryAddressView(LoginRequiredJSONMixin, View):
    """
    需求：
        1.判断用户是否登录
        2.根据传递过来的数据更新指定的地址信息
        3.更新
        4.返回响应
    """

    def put(self, request, address_id):
        # 根据传递过来的数据更新指定的地址信息
        # 接受参数
        json_dict = json.loads(request.body.decode())
        receiver = json_dict.get('receiver')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')

        # 校验参数
        if not all([receiver, province_id, city_id, district_id, place, mobile]):
            return http.HttpResponseBadRequest('缺少必传参数')
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseBadRequest('参数mobile有误')
        if tel:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
                return http.HttpResponseBadRequest('参数tel有误')
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return http.HttpResponseBadRequest('参数email有误')
        try:
            Address.objects.filter(pk=address_id).update(
                user=request.user,
                title=receiver,
                receiver=receiver,
                province_id=province_id,
                city_id=city_id,
                district_id=district_id,
                place=place,
                mobile=mobile,
                tel=tel,
                email=email
            )
            address = Address.objects.get(pk=address_id)
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({"code": RETCODE.DBERR})

        address_dict = {
            "id": address.id,
            "title": address.title,
            "receiver": address.receiver,
            "province": address.province.name,
            "city": address.city.name,
            "district": address.district.name,
            "place": address.place,
            "mobile": address.mobile,
            "tel": address.tel,
            "email": address.email
        }
        return http.JsonResponse({"address": address_dict, "code": RETCODE.OK})

    def delete(self, request, address_id):
        try:
            address = Address.objects.get(pk=address_id)
            address.is_deleted = True
            address.save()
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({"code": RETCODE.DBERR, "errmsg": "删除失败"})
        return http.JsonResponse({"code": RETCODE.OK})


# 设置默认地址
class DefaultAddressView(View):
    def put(self, request, address_id):
        try:
            address = Address.objects.get(pk=address_id)

            request.user.default_address = address
            request.user.save()
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({"code": RETCODE.DBERR, "errmsg": "设置失败！"})

        return http.JsonResponse({"code": RETCODE.OK})


# 修改地址标题
class UpdateTitleAddressView(LoginRequiredJSONMixin, View):
    """
    需求：
        1.判断用户是否登录
        2.接受参数
        3.更新参数
        4.返回响应
    """

    def put(self, request, address_id):
        # 接收参数
        json_dict = json.loads(request.body.decode())
        title = json_dict.get('title')

        # 查询地址
        address = Address.objects.get(pk=address_id)
        # 更新地址标题
        try:
            address.title = title
            address.save()
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({"code": RETCODE.DBERR, "errmsg": "修改地址标题失败！"})
        return http.JsonResponse({"code": RETCODE.OK})


# 修改密码
class ChangePasswordView(LoginRequiredJSONMixin, View):
    def get(self, request):
        context = {
            "password": request.user.password,
            "username": request.user.username
        }
        return render(request, "user_center_pass.html", context=context)

    """
    需求：
        1.判断用户是否登录
        2.接收参数
        3.验证密码格式是否正确、旧密码是否正确、新密码两次是否一样
        4.修改密码
        5.保存密码到数据库中
        6.用户退出登录状态
        7.返回到登录界面
    """

    def post(self, request):
        # 接收参数
        data = request.POST
        old_password = data.get("old_password")
        new_password = data.get("new_password")
        new_password2 = data.get("new_password2")
        # 验证参数
        if not all([old_password, new_password, new_password2]):
            return http.HttpResponseBadRequest("参数不齐！")
        if not re.match(r'^[a-zA-Z0-9_-]{8,20}', new_password):
            return http.HttpResponseBadRequest("密码格式错误！")
        if new_password2 != new_password:
            return http.HttpResponseBadRequest("两次密码不一样！")
        # 验证旧密码是否正确
        if not request.user.check_password(old_password):
            return http.HttpResponseBadRequest("密码错误！")
        try:
            request.user.set_password(new_password)
            request.user.save()
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({"code": RETCODE.DBERR, "errmsg": "密码修改失败！"})
        # 退出用户登录状态
        logout(request)

        response = redirect(reverse("users:login"))
        # 删除用户登录状态
        response.delete_cookie("username")

        return response


# 用户浏览历史记录的添加
class HistoryView(LoginRequiredJSONMixin, View):
    """
    需求：
        当登录用户访问一个商品详情页面的时候，需要让前端发送一个ajax请求将用户信息和sku_id发送给后端

    后端：
        1.接收数据
        2.验证数据
        3.数据入库(redis)
        4.返回数据
    """

    def post(self, request, ):
        # 接收数据
        user = request.user
        data = json.loads(request.body.decode())
        sku_id = data.get("sku_id")
        # 验证数据
        try:
            sku = SKU.objects.get(pk=sku_id)
        except SKU.DoesNotExist:
            return http.JsonResponse({"code": RETCODE.NODATAERR, "errmsg": "没有此分类！"})
        # 数据入库(redis)　列表　去重　有序　　也可以哟内有序集合
        redis_conn = get_redis_connection("history")
        # 添加管道
        pl = redis_conn.pipeline()
        # 先去重 用lrem删除与value 相同的数据
        # redis_conn.lrem(key,count,value)
        pl.lrem("history_%s" % user.id, 0, sku_id)
        pl.lpush("history_%s" % user.id, sku_id)
        # 只保留前5个元素
        pl.ltrim("history_%s" % user.id, 0, 4)
        pl.execute()
        return http.JsonResponse({"code": RETCODE.OK, "errmsg": "ok"})

    # 获取用户浏览记录
    def get(self, request):
        """
        需求：
            1.获取用户信息
            2.连接redis 获取用户信息[1,2,3,4]
            3.对id列表进行遍历查询
                根据id获取详细信息
                将对象转换成字典
            4.返回数据
        """

        #     1.获取用户信息
        user = request.user
        #     2.连接redis 获取用户信息[1,2,3,4]
        redis_conn = get_redis_connection("history")
        ids = redis_conn.lrange("history_%s" % user.id, 0, 4)
        #     3.对id列表进行遍历查询
        skus = []
        for id in ids:
            #         根据id获取详细信息
            sku = SKU.objects.get(pk=id)
            #         将对象转换成字典
            skus.append({
                'id': sku.id,
                'name': sku.name,
                'default_image_url': sku.default_image.url,
                'price': sku.price
            })
        # 4.返回数据
        return http.JsonResponse({"code": RETCODE.OK, "errmsg": "ok", "skus": skus})


# 全部订单
class AllOrdersView(View):
    def get(self, request):
        context = {
            "username": request.user.username
        }
        return render(request, 'user_center_order.html', context=context)
